﻿using AssemblyLoadContextDemo;
using Autodesk.AutoCAD.Internal;
using Autodesk.AutoCAD.Windows.Data;
using load;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Xml.Serialization;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using Path = System.IO.Path;

namespace loads.scr.WPF界面;

public class Dll信息
{
	private bool _开关 = false;
	public bool 开关
	{
		get { return _开关; }
		set
		{
			_开关 = value;
			//路径后置，使界面初始化时不会又加载卸载一次。
			if (!File.Exists(_Dll路径))
				return;

			if (_开关 == true)
				加载dll();
			else
				卸载dll();
			属性更改?.Invoke();
		}
	}

	private bool _自动加载模式 = false;
	public bool 自动加载模式
	{
		get { return _自动加载模式; }
		set
		{
			_自动加载模式 = value;
			//路径后置，使界面初始化时不会又切换一次。
			if (!File.Exists(_Dll路径))
				return;

			if (_自动加载模式 == true)
				AutoLoadMode();
			else
				ManualLoadMode();
			属性更改?.Invoke();
		}
	}

	private string _Dll路径 = string.Empty;
	public string Dll路径
	{
		get { return _Dll路径; }
		set
		{
			_Dll路径 = value;
			if (!File.Exists(_Dll路径))
				return;

			文件系统监视器初始化(_Dll路径);
			属性更改?.Invoke();
		}
	}

	public event Action 属性更改;
	private LoadDll Net80Dll = new();
	//private AssemblyDependent Net48Dll;

	public Dll信息() { }

	public Dll信息(string 路径)
	{
		Dll路径 = 路径;
	}

	private void 加载dll()
	{
		string 无组名的命令列表 = "";
		string 有组名的命令列表 = "";
		BindingFlags 方法类型 = BindingFlags.Instance |
							   BindingFlags.Static |
							   BindingFlags.Public |
							   BindingFlags.NonPublic;
		List<Assembly> Assemblys = [];
#if NET8_0
		Net80Dll.LoadFile(_Dll路径);
		Assemblys = [Net80Dll._Assembly];
#elif NET48


#endif
		foreach (var Assembly in Assemblys)
		{
			foreach (var 程序集类型 in Assembly.GetTypes())
				foreach (var 方法 in 程序集类型.GetMethods(方法类型))
					foreach (var 方法上特性 in 方法.GetCustomAttributes(typeof(CommandMethodAttribute), false))
						if (方法上特性 is CommandMethodAttribute 命令属性)
							if (命令属性.GroupName is null)
								无组名的命令列表 += $"命令：{命令属性.GlobalName};\n";
							else
								有组名的命令列表 += $"命令：{命令属性.GlobalName};组名：{命令属性.GroupName};\n";
		}
		MessageBox.Show($"有组名的命令列表:\n{有组名的命令列表}无组名的命令列表:\n{无组名的命令列表}");
	}

	public void 卸载dll()
	{
		BindingFlags 方法类型 = BindingFlags.Instance | 
							   BindingFlags.Static | 
							   BindingFlags.Public | 
							   BindingFlags.NonPublic;
		List<Assembly> Assemblys = [];
#if NET8_0
		Net80Dll.UnLoad();
		if (Net80Dll._Assembly is null)
			return;

		Assemblys = [Net80Dll._Assembly];
#elif NET48
		//if (Net48Dll is null)
		//	return;

		//Assemblys = Net48Dll.MyLoadAssemblys;
#endif
		//卸载CommandMethod命令（需要命令有分组）
		foreach (var Assembly in Assemblys)
		{
			foreach (var 程序集类型 in Assembly.GetTypes())
				foreach (var 方法 in 程序集类型.GetMethods(方法类型))
					foreach (var 方法上特性 in 方法.GetCustomAttributes(typeof(CommandMethodAttribute), false))
						if (方法上特性 is CommandMethodAttribute 命令属性 && 命令属性.GroupName is not null)
							Utils.RemoveCommand(命令属性.GroupName, 命令属性.GlobalName);
		}
	}


	//dll文件更新后自动加载
	private readonly FileSystemWatcher 文件系统监视器 = new();

	private void 文件系统监视器初始化(string 监视文件路径)
	{
		文件系统监视器.Path = Path.GetDirectoryName(监视文件路径);
		文件系统监视器.EnableRaisingEvents = false;
		文件系统监视器.Filter = "*.dll";
		文件系统监视器.Created -= 监视创建行为;
		文件系统监视器.Created += 监视创建行为;
	}

	private void AutoLoadMode()
	{
		文件系统监视器.EnableRaisingEvents = true;
	}

	private void ManualLoadMode()
	{
		文件系统监视器.EnableRaisingEvents = false;
	}

	private void 监视创建行为(object sender, FileSystemEventArgs e)
	{
		var dm = Acap.DocumentManager;

		if (_开关 == false ||
			e.FullPath != Dll路径 ||
			dm.Count == 0 || 
			dm.MdiActiveDocument.Name.StartsWith("开始"))
			return;

		var doc = dm.MdiActiveDocument;
		加载dll();
	}
}


public partial class 动态加载管理界面 : Window
{
	private readonly string 配置文件路径 = 获取dll的目录() + @"\Dll列表配置.xml";
	private readonly XmlSerializer 设置 = new (typeof(ObservableCollection<Dll信息>));
	private readonly ObservableCollection<Dll信息> Dll列表 = [];
	private int 当前行 = 0;

	public 动态加载管理界面()
	{
		InitializeComponent();
		读取配置();


		Dll列表.CollectionChanged -= Dll列表_CollectionChanged;
		Dll列表.CollectionChanged += Dll列表_CollectionChanged;

		DataGrid表格.ItemsSource = Dll列表;
		DataGrid表格.SelectedIndex = 当前行;
	}

	private void 读取配置()
	{
		if (!File.Exists(配置文件路径))
			return;

		using var reader = new StreamReader(配置文件路径);
		var 读取的Dll列表 = (ObservableCollection<Dll信息>)设置.Deserialize(reader);
		foreach (var item in 读取的Dll列表)
		{
			var dll = item;
			dll.属性更改 += 保存配置;

			Dll列表.Add(dll);
		}
	}

	public void 保存配置()
	{
		using var 文件流 = new StreamWriter(配置文件路径);
		设置.Serialize(文件流, Dll列表);
	}

	private void Dll列表_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
	{

		switch (e.Action)
		{
			case NotifyCollectionChangedAction.Add:
				break;

			case NotifyCollectionChangedAction.Remove:
				//在列表删除dll信息时应该卸载插件
				foreach (Dll信息 removedItem in e.OldItems)
				{
					removedItem.卸载dll();
				}
				break;
			case NotifyCollectionChangedAction.Replace: break;
			case NotifyCollectionChangedAction.Move: break;
			case NotifyCollectionChangedAction.Reset: break;
		}

		保存配置();
	}

	private static string 获取dll的目录(string 文件夹 = "")
	{
#if NET8_0
		var uri完整路径 = new Uri(Assembly.GetExecutingAssembly().Location);
#elif NET48
		var uri完整路径 = new Uri(Assembly.GetExecutingAssembly().CodeBase);
#endif
		var 本地完整路径 = uri完整路径.LocalPath;
		var 本地文件夹路径 = Path.GetDirectoryName(本地完整路径);
		return 本地文件夹路径 + 文件夹;
	}

	private void DataGrid表格_当前选中行(object sender, SelectionChangedEventArgs e)
	{
		if (DataGrid表格.SelectedItem is not Dll信息 selectedDll)
			return;

		for (int i = 0; i < Dll列表.Count; i++) 
			if (selectedDll.Dll路径 == Dll列表[i].Dll路径)
				当前行 = i;
	}

	private void 添加_Click(object sender, RoutedEventArgs e)
	{
		var 文件路径 = new Microsoft.Win32.OpenFileDialog
		{
			Title = "请选择你的插件：",
			Filter = "Dll|*.dll",
		};
		if (文件路径.ShowDialog() != true)
			return;

		var dll文件路径 = 文件路径.FileName;
		foreach (var dll信息 in Dll列表)
		{
			if (dll信息.Dll路径 == dll文件路径)
			{
				MessageBox.Show("当前添加的dll已存在！");
				return; 
			}
		}
		Dll列表.Add(new(dll文件路径));
	}

	private void 上移_Click(object sender, RoutedEventArgs e)
	{
		if (当前行 == 0)
			return;

		Dll列表.Move(当前行, 当前行 - 1);
		DataGrid表格.SelectedIndex = --当前行;
	}

	private void 下移_Click(object sender, RoutedEventArgs e)
	{
		if (当前行 == Dll列表.Count - 1)
			return;

		Dll列表.Move(当前行, 当前行 + 1);
		DataGrid表格.SelectedIndex = ++当前行;
	}
}
